package comm;

// // 数据库接口可能用到的数据库字段值常量UserID: root, 刷卡机, 未知用户

import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;

import biotech.osla.MessageProtos.*;

/**
 * 数据库访问封装类 用到第三方库mysql的JDBC驱动
 * 
 * 注：打开和关闭连接不能并发
 * 
 * @author administrator
 * 
 */
class DBAccess {
	private final String DbUrl;
	private final String JDBCDriver;
	private Connection iDbConnection;

	// debug 可能有多个线程同时调用数据库接口函数，正常运行可删掉
	// // 暂时没有此问题，MainLoop和WebService会调用数据库接口函数，但相互独立（每个线程一个数据库连接）
	// // 调试时可把数据库访问记录写在文件里方便查找
	// 由创建线程负责写文件（单线程对单个数据库接口类对象）
	private Log log;

	DBAccess(Log aLog) {
		this.log = aLog;
		DbUrl = PropertyManager.getProtery("DBURL", "");
		JDBCDriver = PropertyManager.getProtery("JDBCDriver", "com.mysql.jdbc.Driver");

		// this.log.setLevel(0); // debug 正常运行可打开此句，不输出日志
	}

	Log getLog() {
		return this.log;
	}

	boolean openDbConnection() {
		try {
			// if(null != iDbConnection) closeDbConnection();
			Class.forName(JDBCDriver);
			iDbConnection = DriverManager.getConnection(DbUrl);
			this.log.print(Log.info, "数据库连接打开");
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		}
	}

	boolean closeDbConnection() {
		try {
			if (null != iDbConnection)
				iDbConnection.close();
			iDbConnection = null;
			this.log.print(Log.info, "数据库连接关闭");
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		}
	}

	// 访问数据库方法成功返回true，失败（数据库连接异常）返回false，查询结果通过函数参数返回
	// 参数中的aForInit表示是否为初始化（true标识读取初始化列表，false标识读取待同步列表），aUpdateTick获取更新时从数据库读出，标记已同步时写入数据库
	// 标注“选填”的变量若数据库中为null则不赋值
	// 写入数据库时，数据库结构体中有部分数据可以为空，取值时先判断一下该值是否为空（通过has函数）
	// 读数据库时，为null的字段不调对应set即可
	// 参数中到仪器ID为绝对ID

	// "#"表示未完成

	// 读取上线（启用）未关联仪器列表（仪器ID，仪器名称）
	boolean getInstrumentList(InstrumentList.Builder aMsgListBuilder) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询
			statement = iDbConnection.prepareStatement("select ID,name from tinstrument where InstrumentStatusID=231 and TerminalMAC='00:00:00:00:00:00'");
			resultset = statement.executeQuery();
			// 填充
			while (resultset.next()) {
				aMsgListBuilder.addInstrument(Instrument.newBuilder() //
						.setId(resultset.getInt(1)) // 仪器ID
						.setName(resultset.getString(2))); // 仪器名称
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			// 在调试阶段，通常是因为参数错误、违反约束、权限错误或者语句错误导致的，因此不应该运行到这里
			// 这里需要提示
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 读取待同步用户资格列表（aForInit为true表示读取初始化列表，false表示读取待同步列表）
	boolean getUserRightList(final int aInstrumentID, UserRightList.Builder aMsgListBuilder, Int32Num aUpdateTick, boolean aForInit) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询
			if (true == aForInit) {
				statement = iDbConnection.prepareStatement("select UserID,UserRightID,TemporaryRightID,UNIX_TIMESTAMP(ExpireTime),UNIX_TIMESTAMP() from tuserright where (InstrumentID=?)");
			} else {
				statement = iDbConnection
						.prepareStatement("select UserID,UserRightID,TemporaryRightID,UNIX_TIMESTAMP(ExpireTime),UNIX_TIMESTAMP() from tuserright where (ApplySynTick>=ReceiveSynTick) and (InstrumentID=?)");
			}
			statement.setInt(1, aInstrumentID);
			resultset = statement.executeQuery();
			// 填充
			while (resultset.next()) {
				aUpdateTick.setValue(resultset.getInt(5)); // 附加信息
				UserRight.Builder msgBuilder = UserRight.newBuilder();
				msgBuilder.setUserId(resultset.getInt(1)) // 用户ID
						.setRight(resultset.getShort(2))// 用户在本仪器上的资格
						.setRightTemp(resultset.getShort(3))// 用户的临时资格
						.setRightTempExpireTime(resultset.getInt(4)); // 用户临时资格失效时间
				aMsgListBuilder.addUserRight(msgBuilder);
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}

	}

	// 读取待同步用户列表 （待同步列表与仪器有关，初始化列表与仪器无关）（黑名单置必填，待测）
	boolean getUserList(final int aInstrumentID, UserList.Builder aMsgListBuilder, Int32Num aUpdateTick, boolean aForInit) {

		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		Log.println("aForInit："+aForInit);
		try {
			// 查询
			//Brownzw TODO 选择当前付款账号
			if (true == aForInit) {
				statement = iDbConnection
						.prepareStatement("select tuser1.ID as UserID,tuser1.UserState as UserState,"
								+ "case when tuser1.RelatedUserID is null then tuser1.FirstName else tuser2.FirstName end as FirstName,"
								+ "case when tuser1.RelatedUserID is null then tuser1.LastName else tuser2.LastName end as LastName,"
								+ "case when tuser1.RelatedUserID is null then tuser1.MobilePhone1 else tuser2.MobilePhone1 end as MobilePhone,"
								+ "tuser1.CardID as CardID,tuserorganizationattributes.ActivedAccount as ActivedAccount,"
								+ "case when tuser1.RelatedUserID is null then UNIX_TIMESTAMP(tuserorganizationattributes.ExpireOfBlack) else UNIX_TIMESTAMP(tuserorganizationattributes.ExpireOfBlack) end as ExpireOfBlack, "
								+ "UNIX_TIMESTAMP() as UpdateTick "
								+ "from (select * from tuser where tuser.UserState=104) as tuser1 "
								+ "LEFT JOIN tuserorganizationattributes ON tuser1.ID=tuserorganizationattributes.UserID "
								+ "LEFT JOIN tinstrument on tuserorganizationattributes.OrganizationID=Organization_Get_Public_Parent(tinstrument.OrganizationID) "
								+ "left join tuser as tuser2 on tuser1.RelatedUserID=tuser2.ID WHERE tinstrument.ID=?");
				statement.setInt(1, aInstrumentID);
			} else {
				statement = iDbConnection
						.prepareStatement("select tuser1.ID as UserID,tuser1.UserState as UserState,"
								+ "case when tuser1.RelatedUserID is null then tuser1.FirstName else tuser2.FirstName end as FirstName,"
								+ "case when tuser1.RelatedUserID is null then tuser1.LastName else tuser2.LastName end as LastName,"
								+ "case when tuser1.RelatedUserID is null then tuser1.MobilePhone1 else tuser2.MobilePhone1 end as MobilePhone,"
								+ "tuser1.CardID as CardID,tuserorganizationattributes.ActivedAccount as ActivedAccount,"
								+ "case when tuser1.RelatedUserID is null then UNIX_TIMESTAMP(tuserorganizationattributes.ExpireOfBlack) else UNIX_TIMESTAMP(tuserorganizationattributes.ExpireOfBlack) end as ExpireOfBlack,"
								+ "UNIX_TIMESTAMP() as UpdateTick "
								+ "from (select NeedSynDataID from tneedsyndata where (NeedSynDataType=311) and (ApplySynTick>=ReceiveSynTick) "
								+ "and (TargetInstrumentID=?)) as temp_syndata "
								+ "left join tuser as tuser1 on temp_syndata.NeedSynDataID=tuser1.ID "
								+ "LEFT JOIN tuserorganizationattributes ON tuser1.ID=tuserorganizationattributes.UserID "
								+ "LEFT JOIN tinstrument on tuserorganizationattributes.OrganizationID=Organization_Get_Public_Parent(tinstrument.OrganizationID) "
								+ "left join tuser as tuser2 on tuser1.RelatedUserID=tuser2.ID WHERE tinstrument.ID=?");
				statement.setInt(1, aInstrumentID);
				statement.setInt(2, aInstrumentID);
			}
			Log.println("InstrumentID："+aInstrumentID);
			resultset = statement.executeQuery();
			while (resultset.next()) {
				Log.println("用户当前ID："+resultset.getInt(1));
				aUpdateTick.setValue(resultset.getInt(9)); // 附加信息
				// Log.println("用户id" + resultset.getInt(1));
				User.Builder msgBuilder = User.newBuilder() //
						.setId(resultset.getInt(1)) // 用户ID
						.setStatus(resultset.getInt(2)) // 用户状态
				;
				String v = resultset.getString(3);
				Log.println("用户当前FirstName："+resultset.getString(3));
				if (null != v) {
					msgBuilder.setFirstName(resultset.getString(3)); // string用户名字（服务端数据库可能为空-数据异常）
				} else {
					Log.println("*用户数据异常：FirstName为空" + " 用户id" + resultset.getInt(1));
					continue;
				}
				v = resultset.getString(4);
				Log.println("用户当前姓氏："+resultset.getString(4));
				if (null != v) {
					msgBuilder.setLastName(resultset.getString(4)); // string用户姓氏（服务端数据库可能为空-数据异常）
				} else {
					Log.println("*用户数据异常：LastName为空" + " 用户id" + resultset.getInt(1));
					continue;
				}
				v = resultset.getString(5);
				Log.println("用户当前电话号："+resultset.getString(5));
				if (null != v) {
					msgBuilder.setPhone(resultset.getString(5)); // string
																	// 用户电话（服务端数据库可能为空-数据异常）
				} else {
					Log.println("*用户数据异常：MobilePhone1为空" + " 用户id" + resultset.getInt(1));
					continue;
				}
				v = resultset.getString(6);
				Log.println("用户当前一卡通序列号："+resultset.getString(6));
				if (null != v) {
					msgBuilder.setCardSerial(Integer.parseInt(v)); // *用户一卡通序列号
				}
				v = resultset.getString(7);
				Log.println("用户当前付款账号ID："+resultset.getString(7));
				if (null != v) {
					msgBuilder.setAccountId(Integer.parseInt(v)); // *用户当前账户ID
				}
				Log.println("用户当前黑名单失效时间："+resultset.getInt(8));
				msgBuilder.setBlacklistExpireTime(resultset.getInt(8)); // 黑名单失效时间
				aMsgListBuilder.addUser(msgBuilder);
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}

	}

	// 读取待同步账户列表（待同步列表与仪器有关，初始化列表与仪器无关）
	boolean getAccountList(int aInstrumentID, AccountList.Builder aMsgListBuilder, Int32Num aUpdateTick, boolean aForInit) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询
			if (true == aForInit) {
				statement = iDbConnection
						.prepareStatement("select ID,State,ResearchGroupID,FLOOR(Money*100) as Money,FLOOR(InitCredit*100) as InitCredit,FLOOR(NewCredit*100) as CurrentCredit,UNIX_TIMESTAMP(InspireTime) as InspireTime,UNIX_TIMESTAMP() as UpdateTick from taccount where (AccountType=152) and (State=161)");

			} else {
				statement = iDbConnection
						.prepareStatement("select taccount.ID as AccountID,taccount.State as State,taccount.ResearchGroupID as ResearchGroupID,FLOOR(taccount.Money*100) as Money,FLOOR(taccount.InitCredit*100) as InitCredit,FLOOR(taccount.NewCredit*100) as CurrentCredit,UNIX_TIMESTAMP(taccount.InspireTime) as InspireTime,UNIX_TIMESTAMP() as UpdateTick from (select TargetInstrumentID,NeedSynDataID from tneedsyndata where (NeedSynDataType=312) and (ApplySynTick>=ReceiveSynTick) and (TargetInstrumentID=?)) as temp_syndata left join taccount on temp_syndata.NeedSynDataID=taccount.ID");
				statement.setInt(1, aInstrumentID);
			}
			resultset = statement.executeQuery();
			// 填充
			while (resultset.next()) {
				aUpdateTick.setValue(resultset.getInt(8));// 附加信息
				// Log.println("ID" + resultset.getInt(1));
				Account.Builder msgBuilder = Account.newBuilder();
				msgBuilder.setId(resultset.getInt(1)) // 账户ID
						.setStatus(resultset.getInt(2)) // 账户状态
						.setDeposit((int) resultset.getFloat(4)) // 账户余额
						.setCredit((int) resultset.getFloat(5)) // 信用额度
						.setCreditTemp((int) resultset.getFloat(6)) // 临时信用额度
						.setCreditTempExpireTime((int) resultset.getFloat(7));// 临时信用额度失效时间
				String v = resultset.getString(3);
				if (null != v) {
					msgBuilder.setGroupId(resultset.getInt(3)); // 账户所属课题组（服务端可以为空）
				} else {
					// msgBuilder.setGroupId(0);
					Log.println("*账户没有所属课题组，不发给客户端");
					continue;
				}
				aMsgListBuilder.addAccout(msgBuilder);
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}

	}

	// 读取待同步预约记录列表
	boolean getBookingList(int aInstrumentID, BookingList.Builder aMsgListBuilder, Int32Num aUpdateTick, boolean aForInit) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询
			if (true == aForInit) {
				statement = iDbConnection
						.prepareStatement("select ID,UserID,UNIX_TIMESTAMP(StartTime) AS B,UNIX_TIMESTAMP(EndTime) AS E,SessionTypeID,BookingStatusID,UNIX_TIMESTAMP() AS N from tbookingrecord where (BookingStatusID<>1106) and (StartTime>NOW()) and (InstrumentID=?)");
			} else {
				statement = iDbConnection
						.prepareStatement("select ID,UserID,UNIX_TIMESTAMP(StartTime) AS B,UNIX_TIMESTAMP(EndTime) AS E,SessionTypeID,BookingStatusID,UNIX_TIMESTAMP() AS N from tbookingrecord where (BookingStatusID<>1106) and (ApplySynTick>=ReceiveSynTick) and (StartTime>NOW()) and (InstrumentID=?)");
			}
			statement.setInt(1, aInstrumentID);
			resultset = statement.executeQuery();
			// 填充
			while (resultset.next()) {
				aUpdateTick.setValue(resultset.getInt(7));// 附加信息
				aMsgListBuilder.addBooking(Booking.newBuilder() //
						.setId(resultset.getInt(1)) // 预约ID
						.setUserId(resultset.getInt(2)) // 用户ID
						.setStartTime(resultset.getInt(3)) // 开始时间
						.setEndTime(resultset.getInt(4)) // 结束时间
						.setType(resultset.getInt(5)) // 预约类型
						.setStatus(resultset.getInt(6))); // 预约状态
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}

	}

	// 读取待同步临时卡关联列表
	boolean getTempCardBindingList(final int aInstrumentID, TempCardBindingList.Builder aMsgListBuilder, Int32Num aUpdateTick, boolean aForInit, IntArrayList aIntArrayList) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询
			if (true == aForInit) {
				statement = iDbConnection
						.prepareStatement("select ID,CardNumberID,UserID,UNIX_TIMESTAMP(StartTime) AS B,UNIX_TIMESTAMP(EndTime) AS E,UNIX_TIMESTAMP() AS N from ttemporarycardbinding where (EndTime>NOW()) and (InstrumentID=?)");
			} else {
				statement = iDbConnection
						.prepareStatement("select ID,CardNumberID,UserID,UNIX_TIMESTAMP(StartTime) AS B,UNIX_TIMESTAMP(EndTime) AS E,UNIX_TIMESTAMP() AS N from ttemporarycardbinding where (ApplySynTick>=ReceiveSynTick) and (InstrumentID=?)");
			}
			statement.setInt(1, aInstrumentID);
			resultset = statement.executeQuery();
			// 填充
			aIntArrayList.clear();
			while (resultset.next()) {
				aUpdateTick.setValue(resultset.getInt(6)); // 附加信息
				aIntArrayList.add(resultset.getInt(1));
				aMsgListBuilder.addTempCardBinding(//
						TempCardBinding.newBuilder() //
								.setCardSerial(resultset.getInt(2)) // 卡号
								.setUserId(resultset.getInt(3)) // 用户
								.setActiveTime(resultset.getInt(4)) // 生效时间
								.setExpireTime(resultset.getInt(5)) // 失效时间
						);
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}

	}

	// 通过仪器ID查循已绑定的mac地址
	boolean getMacAddr(final int aInstrumentID, String[] aMacAddr) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询
			statement = iDbConnection.prepareStatement("select TerminalMAC from tinstrument where ID=?");
			statement.setInt(1, aInstrumentID);
			resultset = statement.executeQuery();
			// 填充
			if (resultset.next()) {
				aMacAddr[0] = resultset.getString(1);
				return true;
			} else {
				aMacAddr[0] = null;
				return false;
			}
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}

	}

	// 读取系统日历
	boolean getCalendarList(int aInstrumentID, CalendarList.Builder aMsgListBuilder, Int32Num aUpdateTick, UpdateYears aUpdateYears, boolean aForInit) {
		// 从数据库读取指定仪器（仪器ID为aDeviceId）系统日历
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询
			if (true == aForInit) {
				statement = iDbConnection
						.prepareStatement("select TO_DAYS(Calendar) as Day,IsHoliday as IsHoliday,YEAR(Calendar) as Year,UNIX_TIMESTAMP() from tcalendar where Calendar>SUBDATE(now(), INTERVAL 1 DAY)");
			} else {
				statement = iDbConnection
						.prepareStatement("select TO_DAYS(tcalendar.Calendar) as Day,tcalendar.IsHoliday as IsHoliday,YEAR(Calendar) as Year,UNIX_TIMESTAMP() from ( select NeedSynDataID as Year from tneedsyndata where (tneedsyndata.NeedSynDataType=318) and (tneedsyndata.ApplySynTick>=tneedsyndata.ReceiveSynTick) and (tneedsyndata.TargetInstrumentID=?) ) as tmp_year inner join tcalendar on tmp_year.Year=YEAR(tcalendar.Calendar)");
				statement.setInt(1, aInstrumentID);
			}
			resultset = statement.executeQuery();
			// 填充
			while (resultset.next()) {
				aUpdateTick.setValue(resultset.getInt(4));// 附加信息
				aUpdateYears.set(resultset.getInt(3));// 同一年只写一次
				aMsgListBuilder.addCalendar(Calendar.newBuilder() //
						.setDay(resultset.getInt(1)) // 日期
						.setIsHoliday(resultset.getBoolean(2)) // 是否假期
						);
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 读取当前仪器个数
	boolean getInstrumentNum(Int32Num aInstrumentNum) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 获取当前仪器个数
			statement = iDbConnection.prepareStatement("select count(ID) from tinstrument");
			resultset = statement.executeQuery();
			if (resultset.next()) {
				// System.out.println("当期仪器个数：" + resultset.getInt(1));
				aInstrumentNum.setValue(resultset.getInt(1));
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}

	}

	// 读取待同步仪器详细参数??
	// // 从数据库读取指定仪器（仪器ID为aDeviceId）详细信息
	boolean getInstrumentDetail(final int aInstrumentID, InstrumentDetail.Builder aMsgBuilder, Int32Num aUpdateTick, boolean aForInit) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询
			// 初始化时肯定要同步，正常通信时可能需要同步
			// 正常通信时检查是否需要同步
			if (false == aForInit) {
				PreparedStatement statement1 = iDbConnection.prepareStatement("select count(ID) from tinstrument where ((ApplySynTick>=ReceiveSynTick) and (ID=?))");
				statement1.setInt(1, aInstrumentID);
				// Log.println("id" + aInstrumentID);
				ResultSet resultset1 = statement1.executeQuery();
				if (resultset1.next()) {
					if (resultset1.getInt(1) == 0)
						// 不需要同步
						return true; // 在上层检查消息内容是否完整（依赖于消息参数不全是可以为空）
				}

			}
			// 查询同步信息
			statement = iDbConnection
					.prepareStatement("select Name,InstrumentStatusID,MinInterval,BookingHoldingTime,AlertTime,OffDelayTime,MinOffTime,AlertCurrent,UNIX_TIMESTAMP() from tinstrument where ID=?");
			statement.setInt(1, aInstrumentID);
			resultset = statement.executeQuery();
			// 填充
			if (resultset.next()) {
				aUpdateTick.setValue(resultset.getInt(9));// 附加信息
				aMsgBuilder.setId(aInstrumentID) // 仪器ID
						.setName(resultset.getString(1)) // 仪器名称(string)
						.setStatus(resultset.getInt(2)) // 仪器状态
						.setMinInterval(resultset.getInt(3)) // 最小可预约时间段
						.setBookingHoldingTime(resultset.getInt(4))// 预约保护时间
						.setAlertTime(resultset.getInt(5)) // 使用超时提醒时间
						.setOffDelayTime(resultset.getInt(6)) // *断电延时时间（服务端非空）
						.setMinOffTime(resultset.getInt(7)) // *最短重上电时间（服务端非空）
						.setAlertCurrent(resultset.getInt(8)); // *报警电流（服务端非空）
				// String v = resultset.getString(4);
				// if(null != v){
				// aMsgBuilder.setClientSoftwareUpdateVersion(v); // *客户端软件最新版本号
				// }
				return true;
			} else {
				return false;
			}

		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 读取待同步仪器专享时段列表
	boolean getReservationList(final int aInstrumentId, ReservationList.Builder aMsgListBuilder, Int32Num aUpdateTick, boolean aForInit) {
		// 从数据库读取指定仪器（仪器ID为aInstrumentId）的专享时段列表
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询
			if (true == aForInit) {
				// 初始化，已删除的或者过期的，不用传输
				statement = iDbConnection
						.prepareStatement("select ID,GroupID,DayOfWeek,TIME_TO_SEC(StartTime),TIME_TO_SEC(EndTime),UNIX_TIMESTAMP(ActiveTime),UNIX_TIMESTAMP(ExpireTime),UNIX_TIMESTAMP(DeletedTime),UNIX_TIMESTAMP() from tinstrumentreservation where ((ExpireTime>now()) and (DeletedTime is null) and (InstrumentID=?))");
			} else {
				// 同步，只要有改动，都要同步
				statement = iDbConnection
						.prepareStatement("select ID,GroupID,DayOfWeek,TIME_TO_SEC(StartTime),TIME_TO_SEC(EndTime),UNIX_TIMESTAMP(ActiveTime),UNIX_TIMESTAMP(ExpireTime),UNIX_TIMESTAMP(DeletedTime),UNIX_TIMESTAMP() from tinstrumentreservation where ((ApplySynTick>=ReceiveSynTick) and (InstrumentID=?))");
			}
			statement.setInt(1, aInstrumentId);
			resultset = statement.executeQuery();
			// 填充
			while (resultset.next()) {
				aUpdateTick.setValue(resultset.getInt(9));// 附加信息
				Reservation.Builder msgBuilder = Reservation.newBuilder()//
						.setId(resultset.getInt(1)) // 时间段ID
						.setGroupId(resultset.getInt(2)) // 课题组ID
						.setWeek(resultset.getInt(3)) // 星期
						.setStartTime(resultset.getInt(4)) // 开始时间
						.setEndTime(resultset.getInt(5)) // 结束时间
						.setActiveTime(resultset.getInt(6)) // 生效时间
						.setExpireTime(resultset.getInt(7)); // 失效时间
				String v = resultset.getString(8);
				if (null != v) {
					msgBuilder.setDeleteTime(Integer.parseInt(v)); // *删除时间
				}
				aMsgListBuilder.addReservation(msgBuilder);
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 标记账户列表已同步
	boolean setUpdatedForAccountList(int aInstrumentID, AccountList aMsgList, Int32Num aUpdateTick) {
		// 已同步的列表在msgList中
		Log.println("标记账户列表已同步，仪器ID：" + aInstrumentID + " 条数：" + aMsgList.getAccoutCount());
		final int listNum = aMsgList.getAccoutCount(); // 列表条数
		IntArrayList[] idesListes = new IntArrayList[2];
		idesListes[0] = new IntArrayList();
		idesListes[1] = new IntArrayList();
		for (int i = 0; i < listNum; i++) {
			// Log.println("账户ID" + aMsgList.getAccout(i).getId());
			idesListes[0].add(aInstrumentID);
			idesListes[1].add(aMsgList.getAccout(i).getId());

		}
		return this.setUpdated(EUpdateType.AccountList, aUpdateTick, idesListes);
	}

	// 标记预约记录已同步（待测）
	// //关于预约到同步情况处理
	// //同步成功调小麦标记已同步程序
	// //预约失败调 update tbookingrecord set BookingStatusID=1106,ReceiveSynTick=?
	// where(ID=?)
	// //同步失败不作为
	boolean setUpdatedForBookingList(int aInstrumentID, BookingList aMsgList, Int32Num aUpdateTick) {
		// 列表在msgList中
		Log.println("标记预约列表已同步，仪器ID：" + aInstrumentID + " 条数：" + aMsgList.getBookingCount());
		final int listNum = aMsgList.getBookingCount(); // 列表条数
		IntArrayList[] idesListes = new IntArrayList[1];
		idesListes[0] = new IntArrayList();
		for (int i = 0; i < listNum; i++) {
			Booking msg = aMsgList.getBooking(i);
			// Log.println("预约ID" + msg.getId());
			idesListes[0].add(msg.getId());
		}
		return this.setUpdated(EUpdateType.BookingList, aUpdateTick, idesListes);
	}

	// 标记预约同步失败（待测）
	// // 若为status为1105置为1106并标记预约失败，否则不作为
	boolean setUpdatedForBookingListFail(int aInstrumentID, BookingList aMsgList, Int32Num aUpdateTick, NoteList aNoteListToNotify) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		try {
			final int listNum = aMsgList.getBookingCount(); // 列表条数
			Log.println("标记预约失败，仪器ID：" + aInstrumentID + " 条数：" + listNum);
			for (int i = 0; i < listNum; i++) {
				Booking msg = aMsgList.getBooking(i);
				if (1105 == msg.getStatus()) {
					// 同步失败，不再继续同步，需要通知
					// // 查询邮件地址 （若查不到则不发邮件通知）
					UserInfo newUserInfo = new UserInfo();
					if (true == this.getUserInfo(msg.getUserId(), newUserInfo)) {
						NoteAddressList to = new NoteAddressList();
						to.add(newUserInfo.emailAddr);
						aNoteListToNotify.add(NoteBookingFail.getNote() //
								.setFirstName(newUserInfo.firstName) //
								.setLastName(newUserInfo.lastName) //
								.setTo(to) //
								.setBookingID(msg.getId()) //
								.setUserID(msg.getUserId()) //
								.setInstrumentID(aInstrumentID));
					}
					statement = null;
					// 标记数据库预约同步失败
					statement = iDbConnection.prepareStatement("update tbookingrecord set BookingStatusID=1106,ReceiveSynTick=? where (ID=?)");
					statement.setInt(1, aUpdateTick.getValue());
					statement.setInt(2, msg.getId());
					statement.executeUpdate();
				} else {
					// 同步失败，下次刷卡机上线继续同步，不需要通知
					continue;
				}
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 周期性更新预约状态
	// // 主要是手动更新未审批的过期预约
	boolean updateBookingsState() {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		try {
			// 更新预约状态
			CallableStatement statement = null;
			statement = iDbConnection.prepareCall("{CALL Book_UpdateRecordto1104_Proc()}");
			statement.execute();
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 周期性更新预约状态
	// // 主要是针对无刷卡机仪器的已完成预约
	// // 此类预约没有对应读刷卡机，不需要同步，同步标志由web端生成预约时置好，通信服务每天查一下数据库里NoCardUse的仪器的预约，把到期的标记完成
	boolean updateNoCardBookingsState() {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		try {
			// 更新预约状态
			CallableStatement statement = null;
			statement = iDbConnection.prepareCall("UPDATE tbookingrecord INNER JOIN tinstrument ON tbookingrecord.InstrumentID=tinstrument.ID SET tbookingrecord.BookingStatusID=1108 WHERE (tinstrument.NoCardUse=1) AND (tbookingrecord.BookingStatusID=1105) AND (tbookingrecord.BookingModelId=181) AND (tbookingrecord.EndTime<NOW())");
			statement.execute();
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}
	
	// 标记仪器详细参数已同步
	boolean setUpdatedForInstrumentDetail(int aInstrumentID, InstrumentDetail aMsg, Int32Num aUpdateTick) {
		// 已同步的信息在msg中
		Log.println("标记仪器详细信息已同步，仪器ID：" + aMsg.getId());
		IntArrayList[] idesListes = new IntArrayList[1];
		idesListes[0] = new IntArrayList();
		idesListes[0].add(aInstrumentID);
		return this.setUpdated(EUpdateType.InstrumentDetail, aUpdateTick, idesListes);
	}

	// 标记系统日历已同步
	boolean setUpdatedForCalendarList(int aInstrumentID, CalendarList aMsg, Int32Num aUpdateTick, UpdateYears aUpdateYears) {
		// 已同步的信息在msg中
		Log.println("标记系统日历已同步" + "仪器ID：" + aInstrumentID);
		IntArrayList[] idesListes = new IntArrayList[2];
		idesListes[0] = new IntArrayList();
		idesListes[1] = aUpdateYears.get();
		for (int i = 0; i < idesListes[1].size(); i++) {
			idesListes[0].add(aInstrumentID);
		}
		return this.setUpdated(EUpdateType.CalendarList, aUpdateTick, idesListes);
	}

	// 标记全局配置信息已同步
	boolean setUpdatedForGlobalConfig(int aInstrumentID, GlobalConfig aMsg, Int32Num aUpdateTick) {
		// 已同步的信息在msg中
		Log.println("标记全局配置信息已同步，仪器ID：" + aInstrumentID);
		IntArrayList[] idesListes = new IntArrayList[1];
		idesListes[0] = new IntArrayList();
		idesListes[0].add(aInstrumentID);
		return this.setUpdated(EUpdateType.GlobalConfig, aUpdateTick, idesListes);
	}

	// 标记待同步仪器专享时段列表已同步
	boolean setUpdatedForReservationList(int aInstrumentID, ReservationList aMsgList, Int32Num aUpdateTick) {
		// 已同步的列表在msgList中
		Log.println("标记专享已同步，仪器ID：" + aInstrumentID + " 条数：" + aMsgList.getReservationCount());
		final int listNum = aMsgList.getReservationCount(); // 列表条数
		IntArrayList[] idesListes = new IntArrayList[1];
		idesListes[0] = new IntArrayList();
		for (int i = 0; i < listNum; i++) {
			// Log.println("专享ID" + aMsgList.getReservation(i).getId());
			idesListes[0].add(aMsgList.getReservation(i).getId());
		}
		return this.setUpdated(EUpdateType.ReservationList, aUpdateTick, idesListes);
	}

	// 标记临时卡关联列表已同步
	boolean setUpdatedForTempCardBindingList(int aInstrumentID, TempCardBindingList aMsgList, Int32Num aUpdateTick, IntArrayList aIDesList) {
		// 已同步的列表在msgList中
		Log.println("标记临时卡列表已同步，仪器ID：" + aInstrumentID + " 条数：" + aMsgList.getTempCardBindingCount());
		IntArrayList idesListes[] = new IntArrayList[1];
		idesListes[0] = aIDesList;
		return this.setUpdated(EUpdateType.TempCardBindingList, aUpdateTick, idesListes);

	}

	// 标记用户记录已同步
	boolean setUpdatedForUserList(int aInstrumentID, UserList aMsgList, Int32Num aUpdateTick) {
		// 已同步的列表在msgList中
		Log.println("标记用户列表已同步，仪器ID：" + aInstrumentID + " 条数：" + aMsgList.getUserCount());
		final int listNum = aMsgList.getUserCount(); // 列表条数
		IntArrayList[] idesListes = new IntArrayList[2];
		idesListes[0] = new IntArrayList();
		idesListes[1] = new IntArrayList();
		for (int i = 0; i < listNum; i++) {
			// Log.println("用户ID" + aMsgList.getUser(i).getId());
			idesListes[0].add(aInstrumentID);
			idesListes[1].add(aMsgList.getUser(i).getId());
		}
		return this.setUpdated(EUpdateType.UserList, aUpdateTick, idesListes);

	}

	// 标记用户资格列表已同步
	boolean setUpdatedForUserRightList(int aInstrumentID, UserRightList aMsgList, Int32Num aUpdateTick) {
		// 已同步的列表在msgList中
		Log.println("标记资格列表已同步，仪器ID：" + aInstrumentID + " 条数：" + aMsgList.getUserRightCount());
		final int listNum = aMsgList.getUserRightCount(); // 列表条数
		IntArrayList[] idesListes = new IntArrayList[2];
		idesListes[0] = new IntArrayList();
		idesListes[1] = new IntArrayList();
		for (int i = 0; i < listNum; i++) {
			// Log.println("用户ID" + aMsgList.getUserRight(i).getUserId());
			idesListes[0].add(aMsgList.getUserRight(i).getUserId());
			idesListes[1].add(aInstrumentID);
		}
		return this.setUpdated(EUpdateType.UserRightList, aUpdateTick, idesListes);
	}

	// 写入培训用户列表
	boolean setUserInTrainingList(UserInTrainingList aMsgList, IONodeList.DoingForDB aDoingForDB) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		try {
			for (int i = 0; i < aMsgList.getUserInTrainingCount(); i++) {
				UserInTraining msg = aMsgList.getUserInTraining(i);

				// debug
				// System.out.println("**培训用户列表**");
				// System.out.println("使用记录ID:" + msg.getSessionId());
				// System.out.println("卡号:" + msg.getCardSerial());
				// System.out.println("签到时间:" + msg.getCheckInTime());
				// System.out.println("用户ID:" + msg.getUserId());

				// 查用户身份2014.3.19
				UserInfo newUserInfo = new UserInfo();
				getUserInfo(msg.getUserId(), newUserInfo);
				// 写入(可能需要改为insert)
				statement = iDbConnection
						.prepareStatement("replace into tuserintrainingsession (SessionID,CardSerial,UserID,CheckedInTime,CreatedID,CreatedTime,InstrumentID,Manul,UserPosition) values (?,?,?,FROM_UNIXTIME(?),?,now(),?,0,?)");
				// 数据库接口可能用到的UserID: root, 刷卡机, 未知用户
				// 找李炎要刷卡机对应读用户ID，用户ID可以直接打进去
				statement.setLong(1, msg.getSessionId());
				statement.setInt(2, msg.getCardSerial());
				statement.setInt(3, msg.getUserId());
				statement.setInt(4, msg.getCheckInTime());
				statement.setInt(5, 2); // createdID刷卡机：2
				statement.setInt(6, aDoingForDB.getInstrumentID());
				if(0 != newUserInfo.position){
					statement.setInt(7, newUserInfo.position); // 用户身份
				}	else {
					statement.setString(7, null);
				}
				statement.executeUpdate();
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 写入仪器绑定信息
	boolean setInstrumentBinding(InstrumentBinding aMsg) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		try {
			// 仪器绑定信息写入数据库
			// debug
			// System.out.println("仪器ID:" + aMsg.getInstrumentId()); // 仪器ID
			// System.out.println("客户端MAC地址：" + aMsg.getClientMacAddr()); //
			// 客户端MAC地址
			// System.out.println("客户端型号：" + aMsg.getClientModel()); // 客户端型号
			// System.out.println("客户端版本：" + aMsg.getClientVersion()); // 客户端版本
			// System.out.println("是否绑定：" + aMsg.getBinding()); // 是否绑定
			// 写入数据库
			statement = iDbConnection.prepareStatement("update tinstrument set TerminalMAC=?,ControlTypeID=?,TerminalVersion=? where ID=?");

			if (InstrumentBinding.Option.CONFIRM_BINDING == aMsg.getOption()) {
				// 绑定
				statement.setString(1, aMsg.getClientMacAddr());
				statement.setInt(2, aMsg.getClientModel());
				statement.setString(3, aMsg.getClientVersion());
			} else if (InstrumentBinding.Option.RELEASE_BINDING == aMsg.getOption()) {
				// 解绑定
				statement.setString(1, "00:00:00:00:00:00"); // 12个0
				statement.setInt(2, 244); // 244
				statement.setString(3, "v0.00"); // v0.00
			} else {
				// 请求绑定或其他
				return true;
			}
			statement.setInt(4, aMsg.getInstrumentId());
			statement.executeUpdate();

			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}
	
	// 准备仪器离线时间过长短信通知
	// 发送给该仪器读所有仪器管理员
	boolean getNoteInstrumentOffline(final int aInstrumentID, final NoteList aNoteList) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 离线时间过长，通知仪器管理员
			NoteAddressList toes = new NoteAddressList(); // 收件人地址列表
			// 查询仪器所有管理员地址（若查不到则不发通知）
			toes.clear();
			statement = null;
			statement = iDbConnection.prepareStatement("select UserID from tuserright where ((UserRightID=254) or (UserRightID=255)) and (InstrumentID=?)");
			statement.setInt(1, aInstrumentID); // 仪器ID
			resultset = statement.executeQuery();
			while (resultset.next()) {
				UserInfo newUserInfo = new UserInfo();
				if (true == this.getUserInfo(resultset.getInt(1), newUserInfo)) {
					toes.add(newUserInfo.phoneNumer); // 手机号码
				}
			}
			// 获取仪器名称
			String instrumentName = " ";
			statement = iDbConnection.prepareStatement("select Name from tinstrument where ID=?");
			statement.setInt(1, aInstrumentID); // 仪器ID
			resultset = statement.executeQuery();
			if (resultset.next()) {
				instrumentName = resultset.getString(1);
			}
			if(toes.size() > 0) {
				aNoteList.add(NoteSMSInstrumentOffline.getNote()
						.setTo(toes) // 收件人
						.setDetail("管理员您好，[" + instrumentName + "]仪器离线时间过长提醒！") // 
						);//
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}


	// 准备仪器离线故障短信通知
	// 发送给系统管理员
	// 包含：新增离线个数，当前在线个数，总离线个数
	boolean getNoteOfflineTooMany(final NoteList aNoteList, final int aNumofOfflineAdd,  final int aNumofOnline ) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 离线故障通知系统管理员
			NoteAddressList toes = new NoteAddressList(); // 收件人地址列表
			// 查询所有系统管理员地址（若查不到则不发通知）
			toes.clear();
			statement = null;
			statement = iDbConnection.prepareStatement("SELECT userid FROM tauthassignments WHERE itemname=? ");
			statement.setString(1, "132"); // 用户角色为系统管理员
			resultset = statement.executeQuery();
			while (resultset.next()) {
				UserInfo newUserInfo = new UserInfo();
				if (true == this.getUserInfo(resultset.getInt(1), newUserInfo)) {
					toes.add(newUserInfo.phoneNumer); // 手机号码
				}
			}
			// 获取本应在线仪器个数（已绑定且工作状态为正常且未被删除的仪器总数）
			int instrumentNum = 0;
			statement = iDbConnection.prepareStatement("select COUNT(ID) from tinstrument where (TerminalMAC <> '00:00:00:00:00:00') and (InstrumentStatusID = 231) and (DeletedDate is null)");
			resultset = statement.executeQuery();
			if (resultset.next()) {
				instrumentNum = resultset.getInt(1);
			}
			if(toes.size() > 0 && instrumentNum > 0 && instrumentNum >= aNumofOnline) {
				aNoteList.add(NoteSMSOfflineFault.getNote()
						.setTo(toes) // 收件人
						.setDetail("管理员您好，新增离线个数：" + aNumofOfflineAdd + "当前在线个数：" + aNumofOnline + "总离线个数：" + (instrumentNum - aNumofOnline)) // 
						);//
			} else {
				Log.println("离线短信准备失败，info：系统管理员数目" + toes.size() + "已启用仪器个数" + instrumentNum);
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}
	
	
	// 检查惩罚期通知（发送提醒给昨天进入惩罚期或昨天出惩罚期的用户）
	// 惩罚期邮件发送，通信服务实现逻辑：
	// 查用户表找到当天出惩罚期的所有用户（用户使用仪器资格表tuserright中的临时资格过期时间小于当前时间），调存储过程实现加分在用户改动表中插入出惩罚期记录等操作（目前用User_GetCurUserright_Func，希望User_EndPunishUser_Proc）；（注：这些用户第二天发短信，刷新出惩罚期和发邮件顺序先后没有关系）
	// 取用户改动表teventofuser中所有过去一天(0点-0点)进入惩罚期的记录，发送进入惩罚期邮件；取用户改动表中所有过去一天出惩罚期的记录，发送出惩罚期邮件；
	// 数据库用户改动表中可通过事件ID区分进惩罚期（1009）和出惩罚期（1010），通过事件操作者区分通信服务和web端（？目前还存储过程没有留参数，不用区分），通过操作值区分一级惩罚期或二级惩罚期（OperateValue2记录惩罚期临时资格：251未授权，252普通资格）
	boolean checkPunishNote(final NoteList aNoteList) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 获取前一天进或出惩罚期的用户列表
			statement = iDbConnection
					.prepareStatement("select EventType,UserID,OperateValue2 from teventofuser where ((EventType=1009) or (EventType=1010)) and (OperationTime>=?) and (OperationTime<?)");
			// 查询的时间段使用手动拼的datetime字符串（昨天00:00-今天00:00）
			java.util.Calendar rightNow = java.util.Calendar.getInstance();
			String dateTime = rightNow.get(java.util.Calendar.YEAR) + "-" + (rightNow.get(java.util.Calendar.MONTH) + 1) + "-" + (rightNow.get(java.util.Calendar.DAY_OF_MONTH) - 1) + " 00:00:00";
			statement.setString(1, dateTime); // 查询起始时间
			dateTime = rightNow.get(java.util.Calendar.YEAR) + "-" + (rightNow.get(java.util.Calendar.MONTH) + 1) + "-" + (rightNow.get(java.util.Calendar.DAY_OF_MONTH) - 0) + " 00:00:00";
			statement.setString(2, dateTime); // 查询终止时间
			resultset = statement.executeQuery();
			while (resultset.next()) {
				// 准备邮件列表
				UserInfo newUserInfo = new UserInfo();
				getUserInfo(resultset.getInt(2), newUserInfo);
				NoteAddressList to = new NoteAddressList();
				to.clear();
				to.add(newUserInfo.emailAddr);
				System.out.println(resultset.getInt(2));
				if(1009 == resultset.getInt(1)) {
					// 进入惩罚期
					aNoteList.add(NotePunishBegin.getNote()
							.setTo(to)
							.setUserName(newUserInfo.firstName + newUserInfo.lastName)
							.setType(resultset.getInt(3))
							);
				} else if(1010 == resultset.getInt(1)){
					// 出惩罚期
					aNoteList.add(NotePunishEnd.getNote()
							.setTo(to)
							.setUserName(newUserInfo.firstName + newUserInfo.lastName)
							.setType(resultset.getInt(3))
							);
				} else {
					// 出错
					Log.println("**SQL语句出错");
				}
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}
	
	// 更新当天出惩罚期用户的使用资格
	// 查询用户表找到今天（今天00:00-明天00:00）所有出惩罚期用户，逐个调存储过程用户使用资格
	boolean updatePunishEndList(){		
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 获取当天出惩罚期用户列表
			statement = iDbConnection
					.prepareStatement("select UserID,InstrumentID from tuserright where (ExpireTime>=?) and (ExpireTime<?)");
			java.util.Calendar rightNow = java.util.Calendar.getInstance();
			String dateTime = rightNow.get(java.util.Calendar.YEAR) + "-" + (rightNow.get(java.util.Calendar.MONTH) + 1) + "-" + (rightNow.get(java.util.Calendar.DAY_OF_MONTH) + 0) + " 00:00:00";
			statement.setString(1, dateTime); // 查询起始时间
			dateTime = rightNow.get(java.util.Calendar.YEAR) + "-" + (rightNow.get(java.util.Calendar.MONTH) + 1) + "-" + (rightNow.get(java.util.Calendar.DAY_OF_MONTH) + 1) + " 00:00:00";
			statement.setString(2, dateTime); // 查询结束时间
			resultset = statement.executeQuery();
			while (resultset.next()) {
				// 调用存储过程更新用户使用资格（包括加分，增加出惩罚期记录等工作）
				CallableStatement newCallableStatement = iDbConnection.prepareCall("{?=call User_GetCurUserright_Func(?,?)}");
				newCallableStatement.registerOutParameter(1, Types.INTEGER);//第一个占位为输出 
				newCallableStatement.setInt(2, resultset.getInt(1)); // 用户ID
				newCallableStatement.setInt(3, resultset.getInt(2)); // 仪器ID
				newCallableStatement.execute();
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}
	
	// 检查账户，并获取发布邮件通知准备信息，插入账户通知事件
	// 20140104修改：原邮件发给账户建立者和管理者，改为发给管理者
	boolean checkAccount(final NoteList aNoteList) {
		Log.println("检查账户，看是否需要发布通知");
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 获取待通知账户信息
			statement = iDbConnection
					.prepareStatement("select * from (select tmp_account.ID,tmp_account.Money,tmp_account.InitCredit,tmp_event.Event,(case when Money+InitCredit<0 then 1513 when Money<0 then 1512 else 1511 end) as NewEvent from (select ID,Money,InitCredit from taccount where ((AccountType=152) and (State=161) and (Money<(select AccountAlert from tglobalconfig where StartTime<now() order by StartTime desc limit 1)))) as tmp_account left join (select teventofaccount.AccountID,teventofaccount.Event from teventofaccount inner join (select AccountID,max(Time) as LastTime from teventofaccount where (((Event=1511) or (Event=1512) or (Event=1513)) and (Time>SUBDATE(now(), INTERVAL 30 DAY))) group by AccountID) as tmp_lasttime on ((teventofaccount.AccountID=tmp_lasttime.AccountID) and (teventofaccount.Time=tmp_lasttime.LastTime))) as tmp_event on tmp_account.ID=tmp_event.AccountID) as tmp_account2 where ((Event<>NewEvent) or (Event is null))");
			resultset = statement.executeQuery();
			while (resultset.next()) {
				// Log.println("账户ID：" + resultset.getInt(1) + "type:" +
				// resultset.getInt(5)); // debug
				NoteAddressList to = new NoteAddressList(); // 待发邮件地址列表
				//(新添加内容)如果用户是非 活跃 用户（上个月未产生费用）则不发送邮件
				CallableStatement newCallableStatement = iDbConnection.prepareCall("{call Account_CheckActivity_Proc(?,?)}");
				newCallableStatement.registerOutParameter(2, Types.INTEGER);//第一个占位为输出 
				newCallableStatement.setInt(1, resultset.getInt(1)); // 账户ID
				newCallableStatement.execute();
				if(newCallableStatement.getInt(2) == 0){//该用户为非活跃用户
					continue;
				};
				// 获取账户名称（zao）
				String accountName = " ";
				PreparedStatement newStatement = iDbConnection.prepareStatement("select AccountName,CreatedID from taccount where ID=?");
				newStatement.setInt(1, resultset.getInt(1)); // 账户ID
				ResultSet newResultset = newStatement.executeQuery();
				if (newResultset.next()) {
					accountName = newResultset.getString(1);
					// 向账户建立者发邮件通知
					// 通过用户ID查用户Email
					UserInfo newUserInfo = new UserInfo();
					//long num = newResultset.getInt(2);
					if (true == getUserInfo(newResultset.getInt(2), newUserInfo)) {
						to.clear();
						//to.add(newUserInfo.emailAddr);
						// 增加一条邮件
						//aNoteList.add(NoteAccount.getNote() //
						//		.setAccountID(resultset.getInt(1)) // 账户ID
						//		.setMoney(resultset.getFloat(2)) // 账户余额
						//		.setInitCredit(resultset.getFloat(3)) // 信用值
						//		.setType(resultset.getInt(5)) // 通知类型
						//		.setUserName(newUserInfo.firstName + newUserInfo.lastName) // 收件人姓名
						//		.setDetail("提示：\n" + "账户名称：" + accountName + "\n账户余额：" + resultset.getFloat(2) + "\n您作为该账户\"管理者\"的用户登录名：" + newUserInfo.loginName) // 通知信息
						//		.setTo(to) // 邮件地址
						//		);
					}

				}
				// 获取账户管理者信息（主要为邮件地址）（返回用户ID，用户姓，用户名，用户邮件地址）
				newStatement = iDbConnection
						.prepareStatement("select UserID,LoginName,FirstName,LastName,Email from (select UserID from taccountofuser where ((UseRelationship=171) and (AccountID=?))) as tmp_account left join (select tmp1.ID, tmp1.LoginName, case when tmp1.RelatedUserID is null then tmp1.FirstName else tmp2.FirstName end as FirstName, case when tmp1.RelatedUserID is null then tmp1.LastName else tmp2.LastName end as LastName, case when tmp1.RelatedUserID is null then tmp1.Email1 else tmp2.Email1 end as Email from tuser as tmp1 left join tuser as tmp2 on tmp1.RelatedUserID=tmp2.ID) as tmp_user on tmp_account.UserID=tmp_user.ID");
				newStatement.setInt(1, resultset.getInt(1)); // 账户ID
				newResultset = newStatement.executeQuery();
				
				while (newResultset.next()) {
					to.clear();
					to.add(newResultset.getString(5));// 邮件地址
					// 增加一条邮件
					aNoteList.add(NoteAccount.getNote() //
							.setAccountID(resultset.getInt(1)) // 账户ID
							.setMoney(resultset.getFloat(2)) // 账户余额
							.setInitCredit(resultset.getFloat(3)) // 信用值
							.setType(resultset.getInt(5)) // 通知类型
							.setUserName(newResultset.getString(3) + newResultset.getString(4)) // 收件人姓名
							.setDetail("提示：\n" + "付款账户名称：" + accountName + "\n付款账户余额：" + resultset.getFloat(2) + "\n您作为该账户所有者或管理者的用户登录名：" + newResultset.getString(2)) // 通知信息
							.setTo(to) // 邮件地址
							);
				}
				IntArrayList accountIDList = new IntArrayList(); // 临时存事件列表账户ID
				accountIDList.clear();
				accountIDList.add(resultset.getInt(1)); // 账户ID
				this.setAccountEvent(accountIDList, resultset.getInt(5)); // 插入余额不足通知事件
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}

	}

	// 插入余额不足、大客户通知事件 // 待测？？
	// 更新数据库事件表
	private boolean setAccountEvent(final IntArrayList aAccountIDList, final int aEventType) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		try {
			// 插入余额不足、大客户通知事件
			final int year = java.util.Calendar.getInstance().get(java.util.Calendar.YEAR); // 获取当前年份
			for (int i = 0; i < aAccountIDList.size(); i++) {
				final int accountID = aAccountIDList.get(i);
				Log.println("插入余额不足、大客户通知事件：账户ID：" + accountID + " 类型：" + aEventType); // debug
				statement = iDbConnection
						.prepareStatement("insert into teventofaccount (AccountID,Time,Event,Operator,EarlyCredit,Money,EarlyMoney,MoneyTransaction,PartitionID) select ID,now(),?,1,NewCredit,Money,Money,0,? from taccount where ID=?");
				statement.setInt(1, aEventType); // 事件类型
				statement.setInt(2, year - 2000); // 年份-2000
				statement.setInt(3, accountID); // 账户ID
				statement.executeUpdate(); // 1秒钟对同一AccountID调两次后一次会失败（主键重复问题）
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 检查并标记大客户
	boolean checkCharge() {
		Log.println("检查所有账户，看是否为大客户");
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 获取账户支出信息
			final int year = java.util.Calendar.getInstance().get(java.util.Calendar.YEAR); // 获取当前年份
			statement = iDbConnection
					.prepareStatement("select ID from (select taccount.ID,IFNULL(tmp1.Charge,0)+IFNULL(tmp2.Charge,0)+IFNULL(tmp3.Charge,0)+IFNULL(tmp4.Charge,0) as Charge from taccount left join (select AccountID,sum(trecordofuser.HaveCharge) as Charge from trecordofuser where PartitionID=? group by AccountID) as tmp1 on taccount.ID=tmp1.AccountID left join (select AccountID,sum(Price*Quantity) as Charge from tchangingofsupplies where ((Newest=1) and (PartitionID=?)) group by AccountID) as tmp2 on taccount.ID=tmp2.AccountID left join (select AccountID,sum(Price*Quantity) as Charge from tchargingofcompensation where ((Newest=1) and (PartitionID=?)) group by AccountID) as tmp3 on taccount.ID=tmp3.AccountID left join (select AccountID,sum(Charge) as Charge from tchargingofmissappoint where PartitionID=? group by AccountID) as tmp4 on taccount.ID=tmp4.AccountID left join (select AccountID,count(Event) as EventCount from teventofaccount where (((Event=1514) or (Event=1515)) and YEAR(Time)=?) group by AccountID) as tmp5 on taccount.ID=tmp5.AccountID where tmp5.EventCount is null) as tmp_list where Charge>(select VipStandard from tglobalconfig where StartTime<now() order by StartTime desc limit 1)");
			statement.setInt(1, year - 2000);
			statement.setInt(2, year - 2000);
			statement.setInt(3, year - 2000);
			statement.setInt(4, year - 2000);
			statement.setInt(5, year); // 年份
			resultset = statement.executeQuery();
			final IntArrayList accountIDList = new IntArrayList();
			while (resultset.next()) {
				accountIDList.add(resultset.getInt(1));
				// Log.println("账户ID：" + resultset.getInt(1)); // debug
			}
			this.setAccountEvent(accountIDList, 1514); // 插入大客户事件
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 读取全局配置信息
	boolean getGlobalConfig(int aInstrumentID, GlobalConfig.Builder aMsgBuilder, Int32Num aUpdateTick, boolean aForInit) {
		// 从数据库读取指定仪器（仪器ID为aDeviceId）全局配置信息
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询
			// 初始化时肯定需要同步，正常通信时可能需要同步
			// 正常通信时检查是否需要同步
			if (false == aForInit) {
				PreparedStatement statement1 = iDbConnection
						.prepareStatement("select count(TargetInstrumentID) from tneedsyndata where ((NeedSynDataType=319) and (ApplySynTick>=ReceiveSynTick) and (TargetInstrumentID=?))");
				statement1.setInt(1, aInstrumentID);
				ResultSet resultset1 = statement1.executeQuery();
				if (resultset1.next()) {
					if (resultset1.getInt(1) == 0)
						// 不需要同步
						return true; // 在上层检查消息内容是否完整（依赖与消息参数不全是可以为空）
				}
			}
			// 查询同步信息
			statement = iDbConnection.prepareStatement("select AccountAlert,TrainingValidTime,WorkTime,UNIX_TIMESTAMP(),ClientSoftwareUpdateURL,ClientSoftwareAutoUpdate from tglobalconfig where StartTime<now() order by StartTime desc limit 1");
			resultset = statement.executeQuery();
			// 填充
			if (resultset.next()) {
				aUpdateTick.setValue(resultset.getInt(4));// 附加信息
				aMsgBuilder.setAccountDepositLimit(resultset.getInt(1)) // 账户余额提醒线
						.setValidTrainingCheckInTime(resultset.getInt(2)) // 培训报名有效时间
						.setWorkingTime(resultset.getString(3)); // 工作时间（没有空格，分号隔开时间段）
				String v = resultset.getString(5);
				if (null != v) {
					aMsgBuilder.setClientSoftwareUpdateUrl(v); // *客户端软件更新地址
				}
				int i = 6; // 列
				if (null != resultset.getString(i)) {
					aMsgBuilder.setClientSoftwareAutoUpdate(resultset.getInt(i)); // *客户端软件是否自动更新
				}

			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 读出最后一条刷卡记录
	boolean getUserEventListLast(final int aInstrumentID, UserEventList.Builder aMsgListBuilder) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询
			statement = iDbConnection
					.prepareStatement("SELECT ID,UserID,CardSerial,CardType,ActionTypeID,ActionResultID,CreatedTime,GroupID FROM tusereventofterminal WHERE InstrumentID=? ORDER BY CreatedTime DESC LIMIT 0,1");
			statement.setInt(1, aInstrumentID); // 仪器ID
			resultset = statement.executeQuery();
			if (resultset.next()) {
				UserEvent.Builder msgBuilder = UserEvent.newBuilder() //
						.setId(resultset.getLong(1)) // 记录ID
						.setUserId(resultset.getInt(2)) // 用户ID
						.setCardSerial(resultset.getInt(3)) // 卡号
						.setCardType(resultset.getInt(4)) // 卡类型
						.setActionType(resultset.getInt(5)) // 动作类型
						.setActionResult(resultset.getInt(6)) // 动作结果
						.setCreateTime(resultset.getInt(7)) // 记录创建时间
						.setInstrumentId(aInstrumentID) // 仪器ID
				;
				String v = resultset.getString(8);
				if (v != null) {
					msgBuilder.setGroupId(Integer.parseInt(v)); // 用户课题组ID
				}
				aMsgListBuilder.addUserEvent(msgBuilder);
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 写入刷卡机用户事件（即刷卡记录）
	boolean setUserEventList(UserEventList aMsgList, IONodeList.DoingForDB aDoingForDB) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		try {
			for (int i = 0; i < aMsgList.getUserEventCount(); i++) {
				UserEvent msg = aMsgList.getUserEvent(i);

				/*
				 * System.out.println("***用户事件***");
				 * System.out.println("用户事件记录ID:" + msg.getId());
				 * System.out.println("用户ID:" + msg.getUserId()); if (true ==
				 * msg.hasGroupId()) { System.out.println("用户当前课题组ID:" +
				 * msg.getGroupId()); // *可NULL } System.out.println("卡号:" +
				 * msg.getCardSerial()); System.out.println("卡类型ID:" +
				 * msg.getCardType());
				 * System.out.println("); System.out.println(); System.out.println("
				 * 发生时间:" + msg.getCreateTime()); System.out.println("仪器ID--:" +
				 * msg.getInstrumentId());
				 */

				Log.println("用户事件，记录ID:" + msg.getId() + "，动作类型：" + msg.getActionType() + "，动作结果ID:" + msg.getActionResult() + "instrumentID: " + msg.getInstrumentId());

				// 写入用户事件
				if (true == msg.hasGroupId()) {
					statement = iDbConnection
							.prepareStatement("replace into tusereventofterminal (SynTime,ID,TerminalMAC,InstrumentID,UserID,CardSerial,CardType,ActionTypeID,ActionResultID,CreatedTime,GroupID) values(now(),?,?,?,?,?,?,?,?,FROM_UNIXTIME(?),?)");
					statement.setInt(10, msg.getGroupId());
				} else {
					statement = iDbConnection
							.prepareStatement("replace into tusereventofterminal (SynTime,ID,TerminalMAC,InstrumentID,UserID,CardSerial,CardType,ActionTypeID,ActionResultID,CreatedTime) values(now(),?,?,?,?,?,?,?,?,FROM_UNIXTIME(?))");
				}
				statement.setLong(1, msg.getId());
				statement.setString(2, aDoingForDB.getMacAddr());
				statement.setInt(3, msg.getInstrumentId());
				statement.setInt(4, msg.getUserId());
				statement.setInt(5, msg.getCardSerial());
				statement.setInt(6, msg.getCardType());
				statement.setInt(7, msg.getActionType());
				statement.setInt(8, msg.getActionResult());
				statement.setInt(9, msg.getCreateTime());
				statement.executeUpdate();

				// 涉及系统设置的用户事件，修改仪器状态
				int num = 0;
				switch (msg.getActionType()) {
				case 1450:
					num = 231;
					break;
				case 1451:
					num = 232;
					break;
				case 1452:
					num = 233;
					break;
				case 1453:
					num = 234;
					break;
				default:
					num = 0;
					break;
				}
				if (num > 0) {
					PreparedStatement newStatement = null;
					newStatement = iDbConnection.prepareStatement("update tinstrument set instrumentStatusID=? where ID=?");
					newStatement.setInt(1, num);
					newStatement.setInt(2, msg.getInstrumentId());
					newStatement.executeUpdate();
				} else {
					// 其他用户事件不作附加处理
				}

			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}

	}

	/****************************** 暂留Begin ***********************************************************/
	void debugTempCodeBegin() {
	}

	// DEBUG
	// // 使用时间过短扣分计算
	boolean testSession() {
		int numSub = 0;
		int m1 = 10, m2 = 20; // 预约
		int n1 = 20, n2 = 25; // 实际
		final int timeUse = (m2 < n2 ? m2 : n2) - (m1 > n1 ? m1 : n1);
		final float numRatio = ((float) timeUse) / (((float) m2 - (float) m1) / 2);
		if (numRatio < 0) {
			numSub = numSub - 100;
		} else if (numRatio < 1) {
			numSub = numSub - (int) (100 * (1 - numRatio) + 0.5); // 四舍五入
		} else {
			// 正常操作，不扣分
		}
		System.out.println("num" + numSub);
		return true;
	}

	// 内部函数测试
	void debug() {
		/*
		 * IntArrayList newAccountIDList = new IntArrayList();
		 * newAccountIDList.add(1); // 测试账户事件
		 * this.setAccountEvent(newAccountIDList, 1);
		 */
		try {
			System.out.println("DBaccess-debug");
			PreparedStatement statement = null;
			ResultSet resultset = null;
			statement = null;
			// 写入(可能需要改为insert)
			statement = iDbConnection
					.prepareStatement("SELECT userid FROM tauthassignments WHERE itemname=? ");

				statement.setString(1,"132"); // 用户身份

			
				resultset = statement.executeQuery();
				while(resultset.next()) {	
					UserInfo newUserInfo = new UserInfo();
				if (true == this.getUserInfo(resultset.getInt(1), newUserInfo)) {
					System.out.println(resultset.getInt(1) + "name:" + newUserInfo.firstName + newUserInfo.lastName + "phone:" + newUserInfo.phoneNumer);
				}
				}
				

			//statement.executeUpdate();
		
	
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());

		}
	}

	void debugTempCodeEnd() {
	}

	/****************************** 暂留End ***********************************************************/


	// #写入使用记录列表 // from liyan
	// 生成使用计费，失约计费
	// 写记录逻辑已测试
	boolean setClientSessionList(SessionList aMsgList, IONodeList.DoingForDB aDoingForDB) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		// debug
		try {
			for (int i = 0; i < aMsgList.getSessionCount(); i++) {
				Session msg = aMsgList.getSession(i);

				// debug
				/*
				 * System.out.println("***使用记录***");
				 * System.out.println("使用记录ID:" + msg.getId());
				 * System.out.println("用户ID:" + msg.getUserId());
				 * System.out.println("用户资格:" + msg.getUserRight());
				 * System.out.println("卡号:" + msg.getCardSerial());
				 * System.out.println("开始时间:" + msg.getStartTime());
				 * System.out.println("结束时间:" + msg.getEndTime());
				 * System.out.println("type:" + msg.getType());
				 * System.out.println("关联账户ID:" + msg.getAccountId());
				 * System.out.println("关联课题组ID:" + msg.getGroupId());
				 * System.out.println("是否需要惩罚:" + msg.getPenaltyFlag()); if
				 * (msg.hasBookingId() == true) { // 可选项先判断下是否存在
				 * System.out.println("关联预约记录ID:" + msg.getBookingId()); }
				 * System.out.println("仪器ID:" + msg.getInstrumentId());
				 */
				Log.println("使用记录ID:" + msg.getId());
				Log.println("用户ID:" + msg.getUserId());
				Log.println("用户资格:" + msg.getUserRight());
				Log.println("卡号:" + msg.getCardSerial());
				Log.println("开始时间:" + msg.getStartTime());
				Log.println("结束时间:" + msg.getEndTime());
				Log.println("type:" + msg.getType());
				Log.println("关联账户ID:" + msg.getAccountId());
				Log.println("关联课题组ID:" + msg.getGroupId());
				Log.println("是否需要惩罚:" + msg.getPenaltyFlag());
				Log.println("关联预约记录ID:" + msg.getBookingId());
				Log.println("仪器ID:" + msg.getInstrumentId());
				// 写入用户使用记录
				// // type为204时用户事件表和管理员时间表都会写入记录（20131222删去204，204为待刷使用记录，待刷原同时写管理员使用记录和用户使用记录，改为只写管理员使用记录表，不写用户使用记录表，等到完善记录时再生成用户使用记录）
				//if (msg.getType() == 203 || msg.getType() == 204) {
				if (msg.getType() == 203) {
					// 写入数据库
					CallableStatement statement = null;
					statement = iDbConnection.prepareCall("{call Charge_NewRecordofuser_Proc(?,FROM_UNIXTIME(?),FROM_UNIXTIME(?),?,?,?,?,?,?,?,?,?,?,?,?)}");
					statement.setLong(1, msg.getId());
					statement.setInt(2, msg.getStartTime());
					statement.setInt(3, msg.getEndTime());
					if (msg.hasBookingId() == true) {
						statement.setInt(4, msg.getBookingId());
					} else {
						statement.setString(4, null);// 测试时若其他地方参数不合法可能会提示不能为null
					}
					statement.setInt(5, msg.getUserId());
					statement.setInt(6, msg.getAccountId());
					statement.setInt(7, msg.getGroupId());
					statement.setInt(8, msg.getUserRight());
					statement.setInt(9, msg.getCardSerial());
					statement.setInt(10, msg.getInstrumentId());
					statement.setInt(11, 0);
					statement.setInt(12, 1);
					statement.setInt(13, 0);
					statement.setString(14, null);// 测试时若其他地方参数不合法可能会提示不能为null
					statement.setString(15, null);

					statement.execute(); // 写入使用记录

					// 生成使用计费
					CallableStatement states = null;
					states = iDbConnection.prepareCall("{call Charge_NewChargingofusing_Proc(?,?,?,?,?,?,?,?,?,?,?,?)}");
					states.setLong(1, msg.getId());// 使用记录ID
					states.setInt(2, (msg.getEndTime() - msg.getStartTime()) / 60); // 分钟数
					states.setInt(3, 0);// 耗材数量
					// 检查用户是否为校内用户，校内用户不开发票，校外用户开发票
					UserInfo newUserInfo = new UserInfo();
					boolean stateCheck = getUserInfo(msg.getUserId(), newUserInfo, msg.getInstrumentId());
					if(true == stateCheck && (121 == newUserInfo.attritionType || 122 == newUserInfo.attritionType) ) {
						states.setInt(4, 0);// 是否需要开发票
					} else{
						states.setInt(4, 1);// 是否需要开发票
					}
					states.setInt(5, 0); // 是否手动添加
					states.setInt(6, 1);// 创建者用户ID
					states.setInt(7, 0); // 申诉状态，一般填0
					states.setString(8, null); // 申诉时间，一般填NULL

					// // 扣除的信用分（以下扣除信用分情况包括挤占他人，失约，使用时间过短，原则上三种情况不会同时出现，在此兼容可以同时出现情况，若同时出现则信用分累积减，备注只记录最后一条原因）
					// 数据库中扣分为负分2014.3.4
					int numSub = 0; // 待加信用分（负值表示减分）
					String strComment = " "; // 备注
					// // 惩罚扣分（挤占他人时间）
					PreparedStatement state = null;
					ResultSet resultset = null;
					if (msg.getPenaltyFlag() == true) {
						strComment = "挤占他人时间";
						state = iDbConnection.prepareStatement("select OccupyDeductCredit from tglobalconfig where StartTime <=now() ORDER BY StartTime DESC LIMIT 0,1");
						resultset = state.executeQuery();
						if (resultset.next()) {
							numSub = numSub + resultset.getInt(1); // 数据库中为负分
						} else {
							Log.println("查询挤占他人时间信用分扣到数额失败：" + "select OccupyDeductCredit from tglobalconfig where StartTime <=now() ORDER BY StartTime DESC LIMIT 0,1");
						}
					}
					// // 预约与使用不符相关扣分
					// // //失约时扣全部分，使用时间过短（使用时间小于预约时间的一半）时按比例扣分
					state = null;
					resultset = null;
					if (true == msg.hasBookingId()) {
						// 查询预约时间信息
						state = iDbConnection
								.prepareStatement("select UNIX_TIMESTAMP(tbookingrecord.StartTime),UNIX_TIMESTAMP(tbookingrecord.EndTime) from tbookingrecord where tbookingrecord.ID=?");
						state.setInt(1, msg.getBookingId());
						resultset = state.executeQuery();
						if (resultset.next()) {
							final int timeUse = (resultset.getInt(2) < msg.getEndTime() ? resultset.getInt(2) : msg.getEndTime())
									- (resultset.getInt(1) > msg.getStartTime() ? resultset.getInt(1) : msg.getStartTime()); // 使用时间与预约时间的匹配时长
							final float numRatio = ((float) timeUse) / ((float) resultset.getInt(2) - (float) resultset.getInt(1)); //匹配时间长度占预约时间长度的比例
							// 查询待扣信用分
							state = null;
							resultset = null;
							state = iDbConnection.prepareStatement("select DeductCreditMiss,TimeLowerLimit,TimeLowerCredit from tglobalconfig where StartTime <=now() ORDER BY StartTime DESC LIMIT 0,1");
							resultset = state.executeQuery();
							if (resultset.next()) {
								if (numRatio < 0) {
									// 失约扣分
									strComment = "失约";
									numSub = numSub + resultset.getInt(1); // 失约信用分
								} else if (numRatio * 100 < resultset.getInt(2)) { // 匹配时长占预约时长比率小于使用时长过短阈值
									// 使用时间过短
									strComment = "使用时间过短";
									numSub = numSub + (int) (resultset.getInt(3) * (1 - numRatio) + 0.5); // 四舍五入 // 使用时间过短扣除信用分
								} else {
									// 正常操作，不扣分
								}
							} else {
								Log.println("查询扣分数额失败：" + "select DeductCreditMiss,TimeLowerLimit,TimeLowerCredit from tglobalconfig where StartTime <=now() ORDER BY StartTime DESC LIMIT 0,1");
							}							

						} else {
							Log.println("查询查询预约时间信息失败，BookingID:" + msg.getBookingId());
						}
					} else {
						// 没有预约，不扣失约或时间过短信用分
					}
					states.setInt(9, numSub); // 扣除信用分，numSub为负数
					states.setString(10, strComment); // 备注
					states.setString(11, "@p_error"); // 存储过程中为输出参数
					states.setString(12, null); // 存储过程中为输出参数

					states.executeUpdate(); // 使用计费

					Log.println("***使用记录触发使用计费");
				}

				// 写入管理员操作记录表
				if (msg.getType() == 201 || msg.getType() == 202 || msg.getType() == 204) {
					// 写入数据库
					PreparedStatement statement = null;
					// insert 还是 replace
					statement = iDbConnection
							.prepareStatement("replace into trecordofmanager (ID,StartTime,EndTime,BootTime,UserID,Type,ManualAdd,PartitionID,SynTime,CreatedID,CreatedTime,CardID,InstrumentID,ConvertUserRecordID) values(?,FROM_UNIXTIME(?),FROM_UNIXTIME(?),?,?,?,?,year(now())-2000,now(),1,now(),?,?,?)");
					statement.setLong(1, msg.getId());
					statement.setInt(2, msg.getStartTime());
					statement.setInt(3, msg.getEndTime());
					statement.setInt(4, (msg.getEndTime() - msg.getStartTime()) / 60);
					statement.setInt(5, msg.getUserId());
					statement.setInt(6, msg.getType());
					statement.setInt(7, 0); // 非手工添加
					statement.setInt(8, msg.getCardSerial());
					statement.setInt(9, msg.getInstrumentId());
					statement.setString(10, null); // 201,202,304
					statement.executeUpdate();
				}

			}
			// 设置刷卡机节点待同步（如果节点在线）
			aDoingForDB.setNewUpdateReq(EUpdateType.AccountList);
			aDoingForDB.setNewUpdateReq(EUpdateType.UserList);
			aDoingForDB.setNewUpdateReq(EUpdateType.UserRightList);
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, "Exception:" + e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 获取最新使用记录列表
	// 仅初始化使用，实际包括一条管理员使用记录和普通用户使用记录
	boolean getClientSessionListLast(final int aInstrumentID, SessionList.Builder aMsgListBuilder) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询管理员使用记录
			statement = iDbConnection.prepareStatement("SELECT ID,UNIX_TIMESTAMP(StartTime),UNIX_TIMESTAMP(EndTime),Type,UserID,CardID FROM trecordofmanager WHERE (InstrumentID=?) and (CreatedID=1) ORDER BY CreatedTime DESC LIMIT 0,1");
			statement.setInt(1, aInstrumentID); // 仪器ID
			resultset = statement.executeQuery();
			if (resultset.next()) {
				aMsgListBuilder.addSession(Session.newBuilder() //
						.setId(resultset.getLong(1)) // 记录ID
						.setStartTime(resultset.getInt(2)) // 开始时间
						.setEndTime(resultset.getInt(3)) // 结束时间
						.setType(resultset.getInt(4)) // 使用类型
						.setUserId(resultset.getInt(5)) // 用户ID
						.setCardSerial(resultset.getInt(6)) // 卡号
						.setUserRight(0) // 用户资格
						.setAccountId(0) // 关联账户ID
						.setGroupId(0) // 关联课题组ID
						.setPenaltyFlag(false) // 是否需要惩罚
						.setInstrumentId(aInstrumentID) // 仪器ID
						);
			}
			// 查询普通用户使用记录
			statement = null;
			statement = iDbConnection.prepareStatement("SELECT ID,UNIX_TIMESTAMP(StartTime),UNIX_TIMESTAMP(EndTime),UserID,CardID,AccountID,GroupID FROM trecordofuser WHERE (InstrumentID=?) and (CreatedID=1) ORDER BY CreatedTime DESC LIMIT 0,1");
			statement.setInt(1, aInstrumentID); // 仪器ID
			resultset = statement.executeQuery();
			if (resultset.next()) {
				Session.Builder msgBuilder = Session.newBuilder() //
						.setId(resultset.getLong(1)) // 记录ID
						.setStartTime(resultset.getInt(2)) // 开始时间
						.setEndTime(resultset.getInt(3)) // 结束时间
						.setType(0) // 使用类型
						.setUserId(resultset.getInt(4)) // 用户ID
						.setCardSerial(resultset.getInt(5)) // 卡号
						.setUserRight(0) // 用户资格
						.setAccountId(resultset.getInt(6)) // 关联账户ID
						.setGroupId(resultset.getInt(7)) // 关联课题组ID
						.setPenaltyFlag(false) // 是否需要惩罚
						.setInstrumentId(aInstrumentID) // 仪器ID
				;

				msgBuilder.setBookingId(0); // 关联预约记录ID
				aMsgListBuilder.addSession(msgBuilder);
				/*
				 * required int64 id = 1; // 记录ID required int32 start_time = 2;
				 * // 开始时间 required int32 end_time = 3; // 结束时间 required int32
				 * type = 4; // 使用类型 required int32 user_id = 5; // 用户ID
				 * required int32 card_serial = 6; // 卡号 required int32
				 * user_right = 7; // 用户资格 required int32 account_id = 8; //
				 * 关联账户ID required int32 group_id = 9; // 关联课题组ID optional int32
				 * booking_id = 10; // 关联预约记录ID required bool penalty_flag = 11;
				 * // 是否需要惩罚 required int32 instrument_id = 12; // 仪器ID
				 */
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	boolean getSystemEventListLast(final int aInstrumentID, SystemEventList.Builder aMsgListBuilder) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			// 查询
			statement = iDbConnection.prepareStatement("SELECT ID,EventTypeID,EventContent,CreatedTime FROM tsystemeventofterminal WHERE InstrumentID=? ORDER BY CreatedTime DESC LIMIT 0,1");
			statement.setInt(1, aInstrumentID); // 仪器ID
			resultset = statement.executeQuery();
			if (resultset.next()) {
				SystemEvent.Builder msgBuilder = SystemEvent.newBuilder() //
						.setId(resultset.getLong(1)) // 记录ID
						.setEventType(resultset.getInt(2)) // 事件类型
						.setCreateTime(resultset.getInt(4)) // 记录创建时间
						.setInstrumentId(aInstrumentID) // 仪器ID
				;
				String v = resultset.getString(3);
				if (v != null) {
					msgBuilder.setEventContent(Long.parseLong(v));
				}
				aMsgListBuilder.addSystemEvent(msgBuilder);
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// #写入刷卡机系统事件（from liyan） 
	boolean setSystemEventList(SystemEventList aMsgList, IONodeList.DoingForDB aDoingForDB) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		try {
			for (int i = 0; i < aMsgList.getSystemEventCount(); i++) {
				SystemEvent msg = aMsgList.getSystemEvent(i);

				// debug
				Log.println("系统事件:" + "事件记录ID:" + msg.getId() + "，仪器ID:" + msg.getInstrumentId() + "，事件类型ID:" + msg.getEventType() + "事件内容:" + msg.getEventContent());

				// 写入数据库
				PreparedStatement statement = null;
				ResultSet resultset = null;
				statement = iDbConnection
						.prepareStatement("replace into tsystemeventofterminal (ID,TerminalMAC,InstrumentID,EventTypeID,EventContent,CreatedTime,SynTime) values (?,?,?,?,?,FROM_UNIXTIME(?),now())");
				statement.setLong(1, msg.getId());
				statement.setString(2, aDoingForDB.getMacAddr());
				statement.setInt(3, msg.getInstrumentId());
				statement.setInt(4, msg.getEventType());
				if (msg.hasEventContent() == true) {
					statement.setLong(5, msg.getEventContent());
				} else {
					statement.setString(5, null);
				}
				statement.setInt(6, msg.getCreateTime());
				statement.executeUpdate();

				// 事件处理逻辑
				statement = null;
				resultset = null;
				switch (msg.getEventType()) {
				case 1475: {
					// 刷卡机状态变更
					statement = iDbConnection.prepareStatement("update tinstrument set InstrumentStatusID=? where ID=?");
					statement.setLong(1, msg.getEventContent()); // 刷卡机状态
					statement.setInt(2, msg.getInstrumentId()); // 仪器ID
					statement.executeUpdate();
					break;
				}
				case 1476: {
					// 刷卡机版本代码更新
					// // 刷卡机软件更新后产生，通信服务器收到后更新对应仪器的TerminalVersion字段。
					// // 因事件内容为int32，该字段为varchar，需要转换，转换规则：如版本代码为201，则填入字符串2.01，如版本代码为2512,则填入25.12，类推。
					final String TerminalVersion = Long.toString(msg.getEventContent()/100) + "." + Long.toString(msg.getEventContent()%100/10) + Long.toString(msg.getEventContent()%10);
					statement = iDbConnection.prepareStatement("update tinstrument set TerminalVersion=? where ID=?");
					statement.setString(1, TerminalVersion); // 刷卡机代码版本
					statement.setInt(2, msg.getInstrumentId()); // 仪器ID
					statement.executeUpdate();
					break;					
				}				
				case 1481: {
					// 预约完成（如约实验）
					// 增加信用分，更新预约记录（调存储过程实现）
					CallableStatement stat = null;
					stat = iDbConnection.prepareCall("{call Book_UpdateRecordto1108_Proc(?,?)}");
					stat.setLong(1, msg.getEventContent()); // 预约ID
					stat.setInt(2, 1); // 操作者（通信服务）
					stat.execute();
					break;
				}
				case 1482: {
					// 预约过期
					// // 标记预约过期
					statement = iDbConnection.prepareStatement("update tbookingrecord set BookingStatusID=? where ID=?");
					statement.setInt(1, 1104); // 预约过期
					statement.setLong(2, msg.getEventContent()); // 预约ID
					statement.executeUpdate();
					// // 写入失约计费
					CallableStatement stat = null;
					stat = iDbConnection.prepareCall("{call Charge_NewChargingofmissappoint_Proc(?,?,?,?,?)}");
					stat.setLong(1, msg.getEventContent());

					// get UserID
					PreparedStatement states = null;
					ResultSet resultsets = null;
					states = iDbConnection.prepareStatement("select UserID from tbookingrecord where ID=?");
					states.setLong(1, msg.getEventContent());
					resultsets = states.executeQuery();
					if (resultsets.next()) {
						int b = resultsets.getInt(1);
						stat.setInt(2, b);
						stat.setString(3, null);
						stat.setString(4, null);
						stat.setString(5, "@p_error");// 存储过程中为输出参数
						stat.execute();
						Log.println("***预约过期-失约计费（刷卡机系统事件）");
					} else {
						Log.println("**用户ID查询失败（结果为0）：select UserID from tbookingrecord where ID=" + msg.getEventContent());
					}

					break;
				}
				case 1483: {
					// 预约被占用
					statement = iDbConnection.prepareStatement("update tbookingrecord set BookingStatusID=? where ID=?");
					statement.setInt(1, 1111); // 预约被占用
					statement.setLong(2, msg.getEventContent()); // 预约ID
					statement.executeUpdate();
					break;
				}
				case 1484: {
					// 预约终止
					statement = iDbConnection.prepareStatement("update tbookingrecord set BookingStatusID=? where ID=?");
					statement.setInt(1, 1110); // 预约终止
					statement.setLong(2, msg.getEventContent()); // 预约ID
					statement.executeUpdate();
					break;
				}
				case 1485:
					// 进入预约保护时间1：空闲
				case 1486:
					// 进入预约保护时间2：有非预约用户在使用
				case 1487:
					// 进入预约保护时间3：预约用户本人在使用，但使用类型与预约类型不符
				{
					// 若符合提醒条件，则短信通知
					String instrumentName = "";
					int bookingHoldingTime = 0; // 预约保护时间（分钟）
					String bookingStartTime = ""; // 预约开始时间
					String bookingProtectEndTime = ""; // 预约保护结束时间
					// 根据仪器ID查仪器名称和保护时间（分钟）
					statement = null;
					statement = iDbConnection.prepareStatement("select Name,BookingHoldingTime from tinstrument where ID=?");
					statement.setLong(1, msg.getInstrumentId()); // 仪器ID
					resultset = statement.executeQuery();
					if (resultset.next()) {
						instrumentName = resultset.getString(1); // 仪器名称
						bookingHoldingTime = resultset.getInt(2); // 预约保护时间
					}
					// 根据预约ID查到预约开始时间，用户ID
					statement = null;
					statement = iDbConnection.prepareStatement("select UNIX_TIMESTAMP(StartTime),UNIX_TIMESTAMP(),UserID from tbookingrecord where ID=?");
					statement.setLong(1, msg.getEventContent()); // 预约记录ID
					resultset = statement.executeQuery();
					if (resultset.next()) {
						if (resultset.getInt(1) > resultset.getInt(2)) {
							// 符合提醒条件（预约时间大于当前时间）
							// 仪器当前状态
							String instruementState = "";
							if(1485 == msg.getEventType()) {
								instruementState = "空闲";
							} else if(1486 == msg.getEventType()) {
								instruementState = "非预约用户使用";
							} else if(1487 == msg.getEventType()) {
								instruementState = "预约用户本人在使用，但使用类型与预约类型不符";
							} else {
								Log.println("出现异常值：SystemEvent.getEventType()=" + msg.getEventType());
							}
							// 时间信息
							final SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm");
							long startTimeMills = resultset.getInt(1) * 1000l;
							java.util.Date newDate = new java.util.Date(startTimeMills);
							bookingStartTime = timeFormat.format(newDate);
							newDate.setTime(startTimeMills + bookingHoldingTime * 60 * 1000l);
							bookingProtectEndTime = timeFormat.format(newDate);
							// 准备通知
							NoteAddressList smsToes = new NoteAddressList(); // 收件人手机号码列表
							UserInfo newUserInfo = new UserInfo();
							if (true == this.getUserInfo(resultset.getInt(3), newUserInfo)) {
								smsToes.add(newUserInfo.phoneNumer);
								// 生成通知
								NoteList newNoteList = new NoteList();
								newNoteList.add(NoteSMSBookingWarn.getNote() //
										.setTo(smsToes) //
										.setDetail(	newUserInfo.firstName + newUserInfo.lastName + "您好，您预约的仪器[" + instrumentName + "]已进入您专属的预约保护时段，请您如约使用仪器！\n" + "您预约的开始时间：【" + bookingStartTime + "】，预约保护时段结束时刻：【" + bookingProtectEndTime + "】，仪器当前状态：" + instruementState));
								newNoteList.sendAll();
							}
						}
					}
					break;
				}
				case 1491: {
					// 使用时间超长，邮件通知仪器主要管理员及使用者，//短信仅通知使用者（20140424可配置？？）
					NoteAddressList emailToes = new NoteAddressList(); // 收件人email地址列表
					NoteAddressList smsToes = new NoteAddressList(); // 收件人手机号码列表
					// 查询仪器所有管理员Email及手机号码（若查不到则不发通知）
					emailToes.clear();
					statement = null;
					statement = iDbConnection.prepareStatement("select UserID from tuserright where ((UserRightID=254) or (UserRightID=255)) and (InstrumentID=?)");
					statement.setInt(1, msg.getInstrumentId()); // 仪器ID
					resultset = statement.executeQuery();
					while (resultset.next()) {
						UserInfo newUserInfo = new UserInfo();
						if (true == this.getUserInfo(resultset.getInt(1), newUserInfo)) {
							emailToes.add(newUserInfo.emailAddr);
							smsToes.add(newUserInfo.phoneNumer);
						}
					}
					// 查询使用者用户信息
					// 通过刷卡记录ID查用户ID，通过用户ID查用户信息（包括姓名，邮箱，电话）
					String userName = " ";
					String actionTypeInfo = " ";
					String actionTime = "";
					statement = null;
					statement = iDbConnection.prepareStatement("select UserID,ActionTypeID,CreatedTime from tusereventofterminal where ID=?");
					statement.setLong(1, msg.getEventContent()); // 刷卡记录ID
					resultset = statement.executeQuery();
					if (resultset.next()) {
						// 使用者信息
						UserInfo userInfo = new UserInfo();
						if (true == this.getUserInfo(resultset.getInt(1), userInfo)) {
							// 查到用户信息
							userName = userInfo.firstName + userInfo.lastName;
							emailToes.add(userInfo.emailAddr);
							smsToes.add(userInfo.phoneNumer);
						}
						// 动作类型ID转化为字符串
						// // 数据库中ttextondatabase有，也可以通过sql语句查
						final int actionTypeID = resultset.getInt(2); // 动作类型
						switch (actionTypeID) {
						case 1402:
							actionTypeInfo = "实验开机";
							break;
						case 1403:
							actionTypeInfo = "培训开机";
							break;
						case 1404:
							actionTypeInfo = "维护开机";
							break;
						case 1405:
							actionTypeInfo = "待刷开机";
							break;
						default:
							actionTypeInfo = Integer.toString(actionTypeID);
						}
						// 刷卡时间
						final String str = resultset.getString(3); // 日期后边有.0结尾
						actionTime = str.substring(0, str.lastIndexOf('.'));// 如需改变格式需手动转换（sql时间项需加UNIX_TIMESTAMP）
					}
					// 查询仪器信息（仪器名称）
					String instrumentName = " ";
					statement = null;
					statement = iDbConnection.prepareStatement("select Name from tinstrument where ID=?");
					statement.setInt(1, msg.getInstrumentId()); // 仪器ID
					resultset = statement.executeQuery();
					if (resultset.next()) {
						instrumentName = resultset.getString(1);
					}
					// 查询刷卡记录ID（与web端显示ID对应）
					String cardSwipeDispID = " ";
					CallableStatement stat = null;
					stat = iDbConnection.prepareCall("{? = call TerminalIDFormation(?)}");
					stat.registerOutParameter(1, Types.VARCHAR);
					stat.setLong(2, msg.getEventContent());
					stat.execute();
					cardSwipeDispID = stat.getString(1);
					// 生成邮件通知
					NoteList newNoteList = new NoteList();
					newNoteList.add(NoteInstrumentWarn.getNote() //
							.setTo(emailToes) //
							.setDetail( userName + "您好，仪器超长使用提醒！\n" + "仪器名称：" + instrumentName + "，仪器ID：" + msg.getInstrumentId()  + "，使用者姓名：" + userName +  "，开始时间：" + actionTime + "，刷卡记录ID：" + cardSwipeDispID + "，动作类型：" + actionTypeInfo) //
							);
					// 生成短信通知
					newNoteList.add(NoteSMSInstrumentUsingWarn.getNote() // 
							.setTo(smsToes) // 
							.setDetail( userName + "您好，仪器超长使用提醒！\n" +"仪器名称：" + instrumentName + "，开始时间：" +  actionTime + "，动作类型" + actionTypeInfo) // 
							);
					// 发送通知
					newNoteList.sendAll();

					break;
				}
				default:
					// 其他事件直接入库即可
					break;
				}

			}
			aDoingForDB.setNewUpdateReq(EUpdateType.AccountList);
			aDoingForDB.setNewUpdateReq(EUpdateType.UserList);
			aDoingForDB.setNewUpdateReq(EUpdateType.UserRightList);
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}


	// 检查数据库获取各仪器同步需求（执行模块调用）
	// // 将对应仪器节点设置为待同步
	boolean checkNewUpdates(IONodeList.IOUpdateNeedList aIOUpdateNeedList) {
		// Log.println("检查数据库看是否有同步需求");
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		ResultSet resultset = null;
		try {
			aIOUpdateNeedList.setTime(); // 设置更新时间

			// 检查用户信息
			statement = iDbConnection.prepareStatement("select distinct TargetInstrumentID from tneedsyndata where (NeedSynDataType=311) and (ApplySynTick>=ReceiveSynTick)");
			resultset = statement.executeQuery();
			while (resultset.next()) {
				// Log.println("用户表待更新" + "仪器ID：" + resultset.getInt(1)); //
				// debug
				aIOUpdateNeedList.setUpdateNeed((resultset.getInt(1) % 65536), EUpdateType.UserList);
			}

			// 检查账户信息
			statement = iDbConnection.prepareStatement("select distinct TargetInstrumentID from tneedsyndata where (NeedSynDataType=312) and (ApplySynTick>=ReceiveSynTick)");
			resultset = statement.executeQuery();
			while (resultset.next()) {
				// Log.println("账户表待更新" + "仪器ID：" + resultset.getInt(1)); //
				// debug
				aIOUpdateNeedList.setUpdateNeed((resultset.getInt(1) % 65536), EUpdateType.AccountList);
			}

			// 检查资格信息
			statement = iDbConnection.prepareStatement("select distinct InstrumentID from tuserright where (ApplySynTick>=ReceiveSynTick)");
			resultset = statement.executeQuery();
			while (resultset.next()) {
				// Log.println("资格表待更新" + "仪器ID：" + resultset.getInt(1)); //
				// debug
				aIOUpdateNeedList.setUpdateNeed((resultset.getInt(1) % 65536), EUpdateType.UserRightList);
			}

			// 检查临时卡关联信息
			statement = iDbConnection.prepareStatement("update ttemporarycardbinding set ReceiveSynTick=UNIX_TIMESTAMP() where (EndTime<NOW())");
			statement.executeUpdate(); // 先执行此句可减少冗余数据
			statement = iDbConnection.prepareStatement("select distinct InstrumentID from ttemporarycardbinding where (ApplySynTick>=ReceiveSynTick)");
			resultset = statement.executeQuery();
			while (resultset.next()) {
				// Log.println("临时卡关联表待更新" + "仪器ID：" + resultset.getInt(1)); //
				// debug
				aIOUpdateNeedList.setUpdateNeed((resultset.getInt(1) % 65536), EUpdateType.TempCardBindingList);
			}

			// 检查预约信息
			statement = iDbConnection.prepareStatement("select distinct InstrumentID from tbookingrecord where (BookingStatusID<>1106) and (ApplySynTick>=ReceiveSynTick) and (StartTime>NOW())");
			resultset = statement.executeQuery();
			while (resultset.next()) {
				// Log.println("预约表待更新" + "仪器ID：" + resultset.getInt(1)); //
				// debug
				aIOUpdateNeedList.setUpdateNeed((resultset.getInt(1) % 65536), EUpdateType.BookingList);
			}

			// 检查日历信息
			statement = iDbConnection
					.prepareStatement("select distinct TargetInstrumentID from tneedsyndata where (tneedsyndata.NeedSynDataType=318) and (tneedsyndata.ApplySynTick>=tneedsyndata.ReceiveSynTick)");
			resultset = statement.executeQuery();
			while (resultset.next()) {
				// Log.println("日历表待更新" + "仪器ID：" + resultset.getInt(1)); //
				// debug
				aIOUpdateNeedList.setUpdateNeed((resultset.getInt(1) % 65536), EUpdateType.CalendarList);
			}

			// 检查仪器详细信息
			statement = iDbConnection.prepareStatement("select distinct ID from tinstrument where (ApplySynTick>=ReceiveSynTick)");
			resultset = statement.executeQuery();
			while (resultset.next()) {
				// Log.println("仪器详细信息待更新" + "仪器ID：" + resultset.getInt(1)); //
				// debug
				aIOUpdateNeedList.setUpdateNeed((resultset.getInt(1) % 65536), EUpdateType.InstrumentDetail);
			}

			// 检查专享时间段信息
			statement = iDbConnection.prepareStatement("select distinct InstrumentID from tinstrumentreservation where (ApplySynTick>=ReceiveSynTick)");
			resultset = statement.executeQuery();
			while (resultset.next()) {
				// Log.println("专享表待更新" + "仪器ID：" + resultset.getInt(1)); //
				// debug
				aIOUpdateNeedList.setUpdateNeed((resultset.getInt(1) % 65536), EUpdateType.ReservationList);
			}

			// 检查全局配置待更新仪器列表
			statement = iDbConnection.prepareStatement("select TargetInstrumentID from tneedsyndata where ((NeedSynDataType=319) and (ApplySynTick>=ReceiveSynTick))");
			resultset = statement.executeQuery();
			while (resultset.next()) {
				// Log.println("全局配置待更新" + "仪器ID：" + resultset.getInt(1)); //
				// debug
				aIOUpdateNeedList.setUpdateNeed((resultset.getInt(1) % 65536), EUpdateType.GlobalConfig);
			}

			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 标记已同步
	// // 更新数据同步标记，设置为已同步
	// // 参数数组长度只可能为1或2；每10个或20个分一包调存储过程
	private boolean setUpdated(final EUpdateType aUpdateType, final Int32Num aUpdateTick, final IntArrayList[] aIDesListes) {
		// 数据库连接检查
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		// 参数检查
		final int numOfListes = aIDesListes.length;
		int numOfIDes = 0;
		final int packageSize;
		if (1 == numOfListes) {
			numOfIDes = aIDesListes[0].size();
			packageSize = 20; // 标记已同步包大小
		} else if (2 == numOfListes) {
			numOfIDes = aIDesListes[0].size();
			if (numOfIDes != aIDesListes[1].size()) {
				// 数组节点长度不一致
				return false;
			}
			packageSize = 10; // 标记已同步包大小
		} else {
			// 数组长度非法
			return false;
		}
		final int type = aUpdateType.getUpdateTypeNum();
		if (type < 0) {
			return false;
		}

		// 标记同步
		try {
			while (numOfIDes > 0) {
				// 拼字符串
				StringBuilder strBuilder = new StringBuilder();
				for (int i = 0; i < packageSize && numOfIDes > 0; i++, numOfIDes--) {
					// 每packageSize个分一包
					if (0 != i) {
						strBuilder.append(",");
					}
					for (int j = 0; j < numOfListes; j++) {
						if (0 != j) {
							strBuilder.append(":");
						}
						strBuilder.append(aIDesListes[j].get(i));
					}
				}
				String str = strBuilder.toString();
				Log.println("待更新ID列表拼成的字符串：type:" + aUpdateType.toString() + " tick:" + aUpdateTick.getValue() + " str:" + str);

				CallableStatement statement = this.iDbConnection.prepareCall("{call SynData_UpdateReceiveSynTick_Proc(?,?,?)}");
				statement.setInt(1, aUpdateType.getUpdateTypeNum()); // 类型
				statement.setInt(2, aUpdateTick.getValue()); // Tick
				statement.setString(3, str); // 列表
				statement.execute(); // 调试刷卡机通信时暂不开
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	private class UserInfo {
		String firstName = " ";
		String lastName = " ";
		String emailAddr = " ";
		String loginName = " ";
		String phoneNumer = " ";
		int attritionType = 0; // 用户归属类型
		int position = 0; // 用户身份
	}
	
	private boolean getUserInfo(final int aUserID, UserInfo aUserInfo,int InstrumentId){
		boolean result =  getUserInfo(aUserID,aUserInfo);
		PreparedStatement statement = null;
		try {
			statement = iDbConnection.prepareStatement("SELECT AttritionType FROM tuserorganizationattributes LEFT JOIN tinstrument on tuserorganizationattributes.OrganizationID=Organization_Get_Public_Parent(tinstrument.OrganizationID) WHERE tuserorganizationattributes.UserID = ? and tinstrument.ID = ?");
			statement.setInt(1, aUserID); // userID
			statement.setInt(2, InstrumentId); // userID
			ResultSet resultset = statement.executeQuery();
			if (resultset.next()) {
				aUserInfo.attritionType = resultset.getInt(1);
			}
		}catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			aUserInfo.attritionType = 0;
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			aUserInfo.attritionType = 0;
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		} 		
		return result;
	}
	
	// 读取用户信息（用于发邮件时获取邮件地址等辅助信息）
	private boolean getUserInfo(final int aUserID, UserInfo aUserInfo) {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		try {
			// 根据用户ID查email等信息
			// 若RelatedUserID不为null则替换id重查,对于管理员用户返回所关联的普通用户信息，20140501删去此功能，直接返回管理员用户信息
//			statement = iDbConnection.prepareStatement("select FirstName,LastName,Email1,RelatedUserID,LoginName,MobilePhone1,AttritionType,Position from tuser where ID=?");
			statement = iDbConnection.prepareStatement("select FirstName,LastName,Email1,RelatedUserID,LoginName,MobilePhone1,Position from tuser where ID=?");
			statement.setInt(1, aUserID); // userID
			ResultSet resultset = statement.executeQuery();
			if (resultset.next()) {
					aUserInfo.firstName = resultset.getString(1);
					aUserInfo.lastName = resultset.getString(2);
					aUserInfo.emailAddr = resultset.getString(3);
					aUserInfo.loginName = resultset.getString(5);
					aUserInfo.phoneNumer = resultset.getString(6);
					
//					aUserInfo.attritionType = 0;
					
//					if(null != resultset.getString(7)) {
//						aUserInfo.attritionType = resultset.getInt(7);
//					} else {
//						aUserInfo.attritionType = 0;
//					}
					if(null != resultset.getString(7)) {
						aUserInfo.position =  resultset.getInt(7);
					} else {
						aUserInfo.position = 0;
					}
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}

	}

	// 获取数据库连接状态
	boolean getConnectState() {
		if (null == iDbConnection) {
			if (false == openDbConnection()) {
				// 输出日志
				this.log.print(Log.error, "数据库连接失败");
				return false;
			}
		}
		PreparedStatement statement = null;
		try {
			// 测试数据库连接状态
			statement = iDbConnection.prepareStatement("select count(ID) from tinstrument");
			ResultSet resultset = statement.executeQuery();
			if (resultset.next()) {
				// Log.println("select count(ID) from tinstrument：" +
				// resultset.getString(1));
			}
			return true;
		} catch (SQLException e) {
			// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
			this.dealDBException();
			e.printStackTrace();
			Log.println(e);
			this.log.print(Log.error, e.toString());
			return false;
		} catch (Exception e1) {
			e1.printStackTrace();
			Log.println(e1);
			this.log.print(Log.error, "Exception:" + e1.toString());
			return false;
		}
	}

	// 数据库语句执行异常处理
	void dealDBException() {
		// 在程序完善之后，只有数据库异常，才会运行到这里，于是运行下面这句话
		// iDbConnection = null;
	}

}

// int包装类
class Int32Num {
	private int value = 0;

	void setValue(int aNum) {
		this.value = aNum;
	}

	int getValue() {
		return this.value;
	}

}

// 状态类
// 状态类可能不需要（返回值即可表示状态，数据有问题或数据库down掉都只体现在sql异常上）
class Status {
	private boolean value = false;

	Status() {
	}

	Status(boolean aValue) {
		value = aValue;
	}

	void setValue(boolean aValue) {
		value = aValue;
	}

	boolean getValue() {
		return value;
	}
}

// 大小可变到int数组，可用于传ID
class IntArrayList {
	private ArrayList<Integer> array = new ArrayList<Integer>();

	boolean add(int aNum) {
		return this.array.add(Integer.valueOf(aNum));
	}

	int remove(int aIndex) { // 由外部保证aIndex有效性
		return this.array.remove(aIndex).intValue();
	}

	int get(int aIndex) { // 由外部保证aIndex有效性
		return this.array.get(aIndex).intValue();
	}

	int size() {
		return this.array.size();
	}

	void clear() {
		this.array.clear();
	}
}

// ** 待改进

// ？？接口函数有的地方成功了一半？？
// // 一个函数里涉及两条sql语句，前一条成功，后一条失败
// // 使用记录和系统事件中分两步：调试阶段暂时保持，若后一条失败，则返回失败，刷卡机未同步成功会继续发同一条数据，死循环。调试完成后可放宽条件
// //

// 数据库操作到逻辑错误与物理错误（暂仅考虑物理错误，通过调试消除）
// // 读列表的条件有误会读出0条记录（不影响结果）
// // 读单条消息有误，消息生成不完整，不会发送（在消息封装包中处理）
// // 写信息有没有可能失败（可能失败但不会触发sql异常，若实在需要看是否写成功可再查一下看看）
// // 写信息失败暂考虑不返回任何错误
// 同步失败时，比如binding失败或update失败时处理（暂考虑不做处理）

// ** 说明

// 刷卡机同步返回太快（1S内）时可能写数据库同步失败（原因是数据库最小时间1S，不够小），问题不严重，导致的结果时
// // 全库扫描时会再同步一次

// 暂时仅考虑仅一个线程独占数据库连接和数据库接口类
// // 数据库接口日志基于单线程实现

// 调试完成后catch只可能为数据库异常（可报告管理员，并作相应反应）
// // 保证不会因为程序问题或参数问题进入异常

// 数据库访问出现NullPointerException时捕获到异常可能为null（异常由protobuf抛出），暂在异常信息前加"Exception:"

// 注：标记已同步用到的字符串不在生成消息list时拼（因这个包可能被拆，相应字符串还会变）

// 关于通信服务日志是否写数据库（没有必要写，不需要再查）

// 在list中加入到msg的完整性判断可以省略，自身的检查由自己保证